<template>
    <view class="appUploadAlertBox">
        <ac-popup ref="popup" type="center" :isMaskClick="false" @touchmove.stop.prevent>
            <view class="content_popup">
                <!-- 关闭app -->
                <ac-icon v-if="!versionInfo.isForce" class="close" name="closeempty" :size="26" color="#fff"
                    @click="closeUpdate"></ac-icon>
                <!-- 版本提示 -->
                <view class="version" :style="{ color: '#fff' }">v{{ versionInfo.version }}</view>
                <!-- 背景 -->
                <image class="backgroundImg" width="100%" height="100%" src="./img/blue.png"></image>
                <!-- 更新详细信息 -->
                <view class="info center">
                    <text class="title" :style="{ color: '#5e5e5e' }">{{ versionInfo.title }}</text>
                    <!-- 更新内容 -->
                    <scroll-view class="info_desc_scroll" :style="{ color: '#878787' }" scroll-y="true">
                        <rich-text :nodes="versionInfo.content"></rich-text>
                    </scroll-view>
                </view>
                <view class="footer" v-if="versionInfo.platform">
                    <button v-if="downloadSuccess && !wgtInstalled" class="btn" :style="btnStyle" @click="installPackage"
                        :loading="wgtInstalling" :disabled="wgtInstalling">
                        {{ wgtInstalling ? '正在安装....' : '下载完成，立即安装' }}
                    </button>
                    <button v-else-if="wgtInstalled && versionInfo.isWgt" class="btn" :style="btnStyle" @click="restart">
                        安装完毕，点击重启
                    </button>
                    <!-- 更新进度 -->
                    <view class="progress-box flex flex-col items-center" :style="{ color: '#4c4c4c' }"
                        v-else-if="downloading">
                        <progress class="progress" :percent="downLoadPercent" :activeColor="props.themeColor" show-info
                            stroke-width="10" />
                        <view style="width:100%;font-size: 28rpx;display: flex;justify-content: space-around;">
                            <text>安装包下载中，请稍后</text>
                            <text>({{ downloadedSize }}M/{{ packageFileSize || 0 }}M)</text>
                        </view>
                    </view>
                    <!-- 选项 -->
                    <view v-else class="btns flex f-x-b">
                        <!-- IOS -->
                        <view v-if="versionInfo.platform == 'ios'" class="btn confirm" :style="btnStyle"
                            @click="jumpToAppStore">
                            立即跳转更新
                        </view>
                        <!-- android -->
                        <view v-else class="btn confirm" :style="btnStyle" @click="updataApp">
                            立即升级
                        </view>
                    </view>
                    <!-- 短期内不在提醒 -->
                    <view v-if="!versionInfo.isForce" class="notRemind" @click="userNotRemind = !userNotRemind"
                        :class="{ active: userNotRemind }">
                        <ac-icon :name="userNotRemind ? 'checkbox' : 'circle'" :size="32"
                            :color="userNotRemind ? ('' || props.themeColor) : '#9d9d9d'"></ac-icon>
                        <view class="remind-text" :style="{ color: userNotRemind ? '#6b6b6b' : '#9d9d9d' }">
                            {{ intervalAlertUserUpdateDay }}日内不在提醒
                        </view>
                    </view>
                </view>
            </view>
        </ac-popup>
    </view>
</template>

<script lang="ts" setup>

import { computed, getCurrentInstance, ref } from 'vue';
import checkVersion from './checkVersion';

const { proxy } = getCurrentInstance() as any;

interface Props {
    // 用户更新提示时间
    intervalAlertUserUpdateDay?: number;
    /** 更新标题 */
    title?: string;
    // 更新内容，富文本格式
    content?: string;
    // 是否热更新
    isWgt: boolean;
    // 数据 [{name:xxx,value:xxx}]
    list: any;
    // 是否可选
    selected?: boolean;
    // 是否选中
    isChecked?: boolean;
    shadow?: boolean;
    btnColor?: string;
    btnBgColor?: string;
    themeColor?: string;
}

// Props 赋予初始值
const props = withDefaults(defineProps<Props>(), {

    sign: '',
    list: [],
    shadow: true,
    isWgt: false,
    btnColor: '#fff',
    btnBgColor: '',
    themeColor: '#3B82F6',
})


const btnStyle = computed(() => {
    return {
        color: props.btnColor,
        backgroundColor: props.btnBgColor || props.themeColor
    }
})

let intervalAlertUserUpdateDay = 1;

interface StoreInfo {
    priority: string;
    scheme: string;
    enable: boolean;
}

let versionInfo = ref({
    title: '',
    content: '',
    url: '',
    version: '',
    isWgt: false,
    platform: '',
    isForce: false,
    storeList: [] as StoreInfo[],
})

// 下载下载状态
let downloading = ref(false);
// 是否下载完成
let downloadSuccess = ref(false);
// 下载进度
let downLoadPercent = ref(0)
// 目前app已下载大小
let downloadedSize = ref(0)
// app总大小
let packageFileSize = ref(0)

// wgt是否安装中
let wgtInstalling = ref(false)
// wgt是否安装完成
let wgtInstalled = ref(false)

// 要安装的本地包地址
let tempFilePath = ref('')
// 之前的安装的本地包地址
let installForBeforeFilePath = ref('')
// 创建的下载任务
let downloadTask = ref<any>(null)

// 用户上次拒绝的时间
let userLastRefuseTime = uni.getStorageSync('userLastRefuseTime')
// 用户是否短期内不更新
let userNotRemind = ref(false)

/**
 * 检查版本更新
 */
async function checkUpdate(data: { loading: boolean }) {
    console.log("更新检测中...");

    // 如果在用户上次拒绝的时间存在
    if (userLastRefuseTime) {
        // 目标时间戳
        let targetTime = userLastRefuseTime + intervalAlertUserUpdateDay * 24 * 60 * 60 * 1000;
        // 现在时间戳
        let nowTime = (new Date).getTime();
        // 如果目标时间戳大于现在时间戳
        if (targetTime > nowTime) {
            // 并阻止执行
            return;
        } else {
            // 清除拒绝时间
            uni.removeStorageSync('userLastRefuseTime');
        }
    }

    // 检查版本 需要更新时才会触发回调
    checkVersion().then((res: any) => {
        // 非静默更新时触发
        if (!res.isSilently) {

            console.log("触发更新...");
            // this.$refs.popup.open();

            // 读取下载好的包的缓存
            const appDownLoadTempFilePath = uni.getStorageSync('appDownLoadTempFilePath');

            // 更新的版本号
            versionInfo.value.version = res.version;
            // 系统环境
            versionInfo.value.platform = res.platform;
            // 网络下载地址
            versionInfo.value.url = res.url;
            // 跳转的应用市场列表
            versionInfo.value.storeList = res.storeList || [];
            // 更新内容 
            versionInfo.value.content = getContentHTML(res.content);
            // 更新标题
            versionInfo.value.title = res.title || '发现新版本';
            // 是否强制更新
            versionInfo.value.isForce = res.isForce;
            // 是否wgt资源包
            versionInfo.value.isWgt = res.isWgt;

            // 如果已经有下载好的包
            if (appDownLoadTempFilePath && compare(versionInfo.value.version, uni.getStorageSync(
                'appDownLoadTempFilePathVersion')) == 0) {
                tempFilePath.value = appDownLoadTempFilePath;
                downloadSuccess.value = true;
                installForBeforeFilePath.value = appDownLoadTempFilePath;
            } else {
                uni.removeStorageSync('appDownLoadTempFilePath');
                uni.removeStorageSync('appDownLoadTempFilePathVersion');
            }

            // 打开更新提示
            console.log("打开更新弹窗")
            proxy.$refs.popup.open();
        }
    })

}
/**
 * 下载App
 */
function downloadPackage() {
    const { url, version } = versionInfo.value
    if (!downloadTask.value) {
        downloading.value = true;

        //下载包
        downloadTask.value = plus.downloader.createDownload(url, {}, (download, status) => {

            if (status == 200) {
                downloadSuccess.value = true;
                tempFilePath.value = download.filename || '';
                uni.setStorageSync('appDownLoadTempFilePathVersion', version)
                uni.setStorageSync('appDownLoadTempFilePath', tempFilePath);
            }
            // 清空下载进度
            downLoadPercent.value = 0;
            downloadedSize.value = 0;
            packageFileSize.value = 0;
            downloadTask.value = null;
        });

        downloadTask.value.start();

        downloadTask.value.addEventListener("statechanged", (task: any, status: any) => {
            switch (task.state) {
                case 3:
                    // 更新下载进度
                    downLoadPercent.value = Number(parseInt((task.downloadedSize / task.totalSize * 100) + ''));
                    downloadedSize.value = Number((task.downloadedSize / Math.pow(1024, 2)).toFixed(2));
                    packageFileSize.value = Number((task.totalSize / Math.pow(1024, 2)).toFixed(2));
                    break;
            }
        });
    }
}

/**
 * 安装app
 */
function installPackage() {
    // wgt资源包安装
    if (versionInfo.value.isWgt) {
        wgtInstalling.value = true;
    }
    plus.runtime.install(tempFilePath.value, {
        force: false
    }, async res => {
        wgtInstalling.value = false;
        wgtInstalled.value = true;
    }, async err => {
        console.log(err)
        downloadSuccess.value = false;
        // 如果是安装之前的包，安装失败后删除之前的包
        if (installForBeforeFilePath.value) {
            await deleteSavedFile(installForBeforeFilePath.value)
            installForBeforeFilePath.value = '';
        }

        uni.showToast({
            title: '更新失败，请重新下载',
            icon: 'none',
            mask: true
        })

    })
}

/**
 * 保存文件
 */
function saveFile(tempFilePath: string) {
    return new Promise((resolve, _reject) => {
        uni.saveFile({
            tempFilePath: tempFilePath,
            success: (_res) => {
                // const savedFilePath = res.savedFilePath;
                uni.setStorageSync('appDownLoadTempFilePath', tempFilePath)
            },
            complete() {
                resolve(true)
            }
        })
    })
}

/**
 * 删除保存的文件
 */
function deleteSavedFile(tempFilePath: string) {
    uni.removeStorageSync('appDownLoadTempFilePath')
    uni.removeSavedFile({
        filePath: tempFilePath,
    })
}

/**
 * 版本比对
 */
function compare(v1 = '0', v2 = '0') {
    let v1Arr = String(v1).split('.')
    let v2Arr = String(v2).split('.')
    const minVersionLens = Math.min(v1Arr.length, v2Arr.length);

    let result = 0;
    for (let i = 0; i < minVersionLens; i++) {
        const curV1 = Number(v1Arr[i])
        const curV2 = Number(v2Arr[i])

        if (curV1 > curV2) {
            result = 1
            break;
        } else if (curV1 < curV2) {
            result = -1
            break;
        }
    }

    if (result === 0 && (v1Arr.length !== v2Arr.length)) {
        const v1BiggerThenv2 = v1Arr.length > v2Arr.length;
        const maxLensVersion = v1BiggerThenv2 ? v1Arr : v2Arr;
        for (let i = minVersionLens; i < maxLensVersion.length; i++) {
            const curVersion = Number(maxLensVersion[i])
            if (curVersion > 0) {
                v1BiggerThenv2 ? result = 1 : result = -1
                break;
            }
        }
    }

    return result;
}


/**
 * 获取更新内容片段
 */
function getContentHTML(content: string) {
    let contentArr = content.split('\n');
    return contentArr.map((item: string) => `<p>${item}</p>`).join('\n')
}

/**
 * 跳转应用市场
 */
function checkStoreScheme(): Promise<void> {
    /**
     * 跳转应用市场逻辑
     * 如果本次更新设置了需要跳转的应用市场则从整个列表中筛选出来启用的应用市场
     * 按照设置的优先级(priority)从大到小排序
     * 并尝试跳转到所有应用市场
     * 如果都跳转失败的话则会显示失败
     */
    // 可以跳转的应用市场
    const canStoreList = (versionInfo.value.storeList || []).filter(item => item.enable)

    let openSchemePromise: any;
    if (canStoreList && canStoreList.length) {
        canStoreList
            .sort((cur, next) => next.priority - cur.priority)
            .map(item => item.scheme)
            .reduce((promise, cur, curIndex) => {
                openSchemePromise = (promise || (promise = Promise.reject())).catch(() => {
                    return new Promise((resolve, reject) => {
                        plus.runtime.openURL(cur, (err) => {
                            reject(err)
                        })
                    })
                })
                return openSchemePromise
            }, openSchemePromise)
        return openSchemePromise
    }

    return Promise.reject()
}

/**
 * 跳转appstore
 */
function jumpToAppStore() {
    // 请填入appid
    plus.runtime.openURL(versionInfo.value.url);
}

/**
 * 更新用户拒绝时间
 */
function updataUserRefuseTime() {
    // 存储用户暂不升级的时间戳
    userLastRefuseTime.value = (new Date).getTime();
    uni.setStorageSync('userLastRefuseTime', userLastRefuseTime.value);
}

/**
 * 关闭更新框
 */
function closeUpdate() {
    if (downloading.value) {
        uni.showModal({
            title: '是否取消下载？',
            cancelText: '否',
            confirmText: '是',
            success: res => {
                if (res.confirm) {
                    downloadTask.value && downloadTask.value.abort();
                    proxy.$refs.popup.close();
                }
            }
        });
    } else {
        proxy.$refs.popup.close();
        // 如果用户短期内不更新
        if (userNotRemind.value) {
            updataUserRefuseTime();
        }
    }

    if (downloadSuccess.value) {
        // 包已经下载完毕，稍后安装，将包保存在本地
        saveFile(tempFilePath.value)
    }


}

/**
 * 重启应用
 */
function restart() {
    wgtInstalled.value = false;
    //更新完重启app
    plus.runtime.restart();
}

/**
 * 应用更新
 */
function updataApp() {
    // 检查可跳转的应用市场 如果失败则走应用内更新
    checkStoreScheme().catch(() => {
        downloadPackage()
    })
}

defineExpose({
    checkUpdate,
})
</script>

<style lang="scss" scoped>
.appUploadAlertBox {
    :deep(.uni-popup) {
        z-index: 1000;
    }

    .bg {
        width: 100%;
    }

    .content_popup {
        width: 590rpx;
        border-radius: 10rpx;
        background-size: cover;
        background-repeat: no-repeat;
        background-position: center;
        box-sizing: border-box;
        background-color: #FFF;
        padding-bottom: 40rpx;
        position: relative;

        .close {
            position: absolute;
            right: 15rpx;
            top: 15rpx;
            z-index: 3;
        }

        .version {
            position: absolute;
            left: 40rpx;
            top: 45rpx;
            z-index: 3;
            font-size: 75rpx;
        }

        .backgroundImg {
            width: 100.1%;
            height: 270rpx;
            position: absolute;
            top: -48rpx;
        }

        .info {
            position: relative;
            padding: 240rpx 40rpx 0;
            z-index: 2;

            .title {
                font-size: 42rpx;
            }

            .info_desc_scroll {
                margin-top: 20rpx;
                font-size: 33rpx;
                min-height: 200rpx;
                max-height: 400rpx;
                box-sizing: border-box;
                line-height: 1.3;

                p:not(:last-child) {
                    margin-bottom: 12rpx;
                }
            }
        }

        .footer {
            padding: 0 30rpx;

            .progress-box {
                width: 100%;
                margin-top: 25rpx;
            }

            :deep(.progress) {
                width: 90%;
                height: 40rpx;
                margin-bottom: 5rpx;

                .uni-progress-bar {
                    border-radius: 35rpx;

                    .uni-progress-inner-bar {
                        border-radius: 35rpx;
                    }
                }
            }

            .btn {
                margin-top: 35rpx;
                height: 75rpx;
                line-height: 75rpx;
                border-radius: 14rpx;
                font-size: 34rpx;
                font-weight: 400;
                text-align: center;
                width: 100%;
            }

            .notRemind {
                display: flex;
                justify-content: center;
                align-items: center;
                margin-top: 24rpx;
                height: 40rpx;
                line-height: 40rpx;

                .remind-text {
                    color: #9d9d9d;
                    font-size: 30rpx;
                    margin-left: 3rpx;
                    transition: color 80ms linear;
                }
            }

        }
    }

    .close-img {
        width: 70rpx;
        height: 70rpx;
        z-index: 1000;
        position: absolute;
        bottom: -120rpx;
        left: calc(50% - 70rpx / 2);
    }
}
</style>